use std::{mem::MaybeUninit, net::SocketAddr};

use conn::{new_conn, SharedConn};
use dashmap::DashMap;
use tokio::net::{TcpListener, TcpStream};

use crate::{
    config::DEVICE_TCP_ADDR,
    error::{new_err, AppErr},
};

pub mod conn;
mod frame;
mod reader;
mod service;

pub type ConnMap = DashMap<i64, SharedConn>;

static mut CONN_MAP: MaybeUninit<ConnMap> = MaybeUninit::uninit();

pub fn init() -> Result<(), AppErr> {
    unsafe {
        CONN_MAP.write(DashMap::new());
    }
    tokio::spawn(run());
    Ok(())
}

pub fn get_conn_map() -> &'static ConnMap {
    unsafe { CONN_MAP.assume_init_ref() }
}

async fn run() {
    let ret = run_impl().await;
    if let Err(err) = ret {
        println!("tcp serve:{}", err);
    }
}

async fn create_conn(addr: SocketAddr, stream: TcpStream) {
    let ret = new_conn(addr, stream).await;
    if let Err(e) = ret {
        println!("conn:{}", e);
    }
}

async fn run_impl() -> Result<(), AppErr> {
    println!("TCP run:{}", DEVICE_TCP_ADDR);
    let server = TcpListener::bind(DEVICE_TCP_ADDR).await?;
    loop {
        let (stream, addr) = server.accept().await?;
        tokio::spawn(create_conn(addr, stream));
    }
}

pub fn get_conn_by_id(id: i64) -> Result<SharedConn, AppErr> {
    let item = get_conn_map()
        .get(&id)
        .ok_or(new_err("没有找到对应的在线设备"))?;
    Ok(item.value().clone())
}

pub fn get_conn(id: i64) -> Option<SharedConn> {
    let item = get_conn_map().get(&id);
    if let Some(item) = item {
        return Some(item.value().clone());
    }
    None
}

